#include "C3DS_Loader.h"
#include "Object.h"
#include "Scene.h"


#define MAIN3DS			0x4D4D
#define MAIN_VERS		0x0002
#define EDIT3DS			0x3D3D
#define MESH_VERS		0x3D3E
#define OBJECT			0x4000
#define TRIG_MESH		0x4100
#define VERT_LIST		0x4110
#define FACE_DESC		0x4120
#define FACE_MAT		0x4130
#define TEX_VERTS		0x4140
#define SMOOTH_GROUP	0x4150
#define LOCAL_COORDS	0x4160
#define MATERIAL		0xAFFF
#define MAT_NAME		0xA000
#define MAT_AMBIENT		0xA010
#define MAT_DIFFUSE		0xA020
#define MAT_SPECULAR	0xA030
#define MAT_SHININESS   0xA040
#define SHINY_PERC		0xA040
#define SHINY_STR_PERC	0xA041
#define TRANS_PERC		0xA050
#define TRANS_FOFF_PERC	0xA052
#define REF_BLUR_PERC	0xA053
#define RENDER_TYPE		0xA100
#define SELF_ILLUM		0xA084
#define MAT_SELF_ILPCT	0xA08A
#define WIRE_THICKNESS	0xA087
#define MAT_TEXMAP		0xA200
#define MAT_MAPNAME		0xA300
#define ONE_UNIT		0x0100
#define KEYF3DS			0xB000
#define FRAMES			0xB008
#define MESH_INFO		0xB002
#define HIER_POS		0xB030
#define HIER_FATHER		0xB010
#define PIVOT_PT		0xB013
#define TRACK00			0xB020
#define TRACK01			0xB021
#define TRACK02			0xB022
#define	COLOR_RGB		0x0010
#define COLOR_TRU		0x0011
#define COLOR_TRUG		0x0012
#define COLOR_RGBG		0x0013
#define PERC_INT		0x0030
#define PERC_FLOAT		0x0031


using namespace RayTrace;
using namespace std;

C3DS_Loader::C3DS_Loader(void):	pScene(NULL),
								bin3ds(NULL)
								/*modelname(NULL),
								path(NULL)*/
{

}

C3DS_Loader::~C3DS_Loader(void)
{
}

bool RayTrace::C3DS_Loader::Load( std::string filename,CScene * Scene )
{
	pScene=Scene;

	ChunkHeader main;

	// strip "'s
	char *name=const_cast<char*>(filename.c_str());
	if (strstr(name, "\""))
		name = strtok(name, "\"");

	// Find the path
	if (strstr(name, "/") || strstr(name, "\\"))
	{
		// Holds the name of the model minus the path
		char *temp;

		// Find the name without the path
		if (strstr(name, "/"))
			temp = strrchr(name, '/');
		else
			temp = strrchr(name, '\\');

		// Allocate space for the path
		char *path = new char[strlen(name)-strlen(temp)+1];

		// Get a pointer to the end of the path and name
		char *src = name + strlen(name) - 1;

		// Back up until a \ or the start
		while (src != path && !((*(src-1)) == '\\' || (*(src-1)) == '/'))
			src--;

		// Copy the path into path
		memcpy (path, name, src-name);
		path[src-name] = 0;
		mPath=string(path);
		//delete [] path;
	}


	// Load the file
	bin3ds = fopen(name,"rb");

	// Make sure we are at the beginning
	fseek(bin3ds, 0, SEEK_SET);

	// Load the Main Chunk's header
	fread(&main.id,sizeof(main.id),1,bin3ds);
	fread(&main.len,sizeof(main.len),1,bin3ds);

	// Start Processing
	MainChunkProcessor(main.len, ftell(bin3ds));

	// Don't need the file anymore so close it
	fclose(bin3ds);

	// Calculate the vertex normals

	CalculateNormals();//it's really needed?

	//// For future reference
	//modelname = name;

	// Find the total number of faces and vertices



	// If the object doesn't have any texcoords generate some
	//for (size_t k = 0; k < pScene->GetObjectsNum(); k++)
	//{
	//	if (pScene->Objects[k].TexCoords.size() == 0)
	//	{
	//		// Set the number of texture coords
	//		pScene->Objects[k].TexCoords.resize(pScene->Objects[k].Vertexes.size());

	//		// Allocate an array to hold the texture coordinates
	//	//	pScene->Objects[k].TexCoords = new GLfloat[pScene->Objects[k].numTexCoords * 2];

	//		// Make some texture coords
	//		for (int m = 0; m < pScene->Objects[k].numTexCoords; m++)
	//		{
	//			pScene->Objects[k].TexCoords[m].u = pScene->Objects[k].Vertexes[m].x;
	//			pScene->Objects[k].TexCoords[m].v = pScene->Objects[k].Vertexes[m].y;
	//		}
	//	}
	//}

	// Let's build simple colored textures for the materials w/o a texture
	//for (int j = 0; j < pScene->GetMaterialsNum(); j++)
	//{
	//	if (pScene->Materials[j].textured == false)
	//	{
	//		unsigned char r = Materials[j].color.r;
	//		unsigned char g = Materials[j].color.g;
	//		unsigned char b = Materials[j].color.b;
	//		Materials[j].tex.BuildColorTexture(r, g, b);
	//		Materials[j].textured = true;
	//	}
	//}

	return true;

}

void RayTrace::C3DS_Loader::ColorChunkProcessor( long length, long findex,vector4 &vec4 )
{
	ChunkHeader h;

	// move the file pointer to the beginning of the main
	// chunk's data findex + the size of the header
	fseek(bin3ds, findex, SEEK_SET);

	while (ftell(bin3ds) < (findex + length - 6))
	{
		fread(&h.id,sizeof(h.id),1,bin3ds);
		fread(&h.len,sizeof(h.len),1,bin3ds);

		// Determine the format of the color and load it
		switch (h.id)
		{
		case COLOR_RGB	:
			// A rgb float color chunk
			FloatColorChunkProcessor(h.len, ftell(bin3ds), vec4);
			break;
		case COLOR_TRU	:
			// A rgb int color chunk
			IntColorChunkProcessor(h.len, ftell(bin3ds), vec4);
			break;
		case COLOR_RGBG	:
			// A rgb gamma corrected float color chunk
			FloatColorChunkProcessor(h.len, ftell(bin3ds), vec4);
			break;
		case COLOR_TRUG	:
			// A rgb gamma corrected int color chunk
			IntColorChunkProcessor(h.len, ftell(bin3ds), vec4);
			break;
		default			:
			break;
		}

		fseek(bin3ds, (h.len - 6), SEEK_CUR);
	}

	// move the file pointer back to where we got it so
	// that the ProcessChunk() which we interrupted will read
	// from the right place
	fseek(bin3ds, findex, SEEK_SET);
}

void RayTrace::C3DS_Loader::PercentChunkProcessor( long length, long findex,float& f)
{
	ChunkHeader h;
	fseek(bin3ds, findex, SEEK_SET);

	fread(&h.id,sizeof(h.id),1,bin3ds);
	fread(&h.len,sizeof(h.len),1,bin3ds);

	// Determine the format of the color and load it

	switch (h.id)
	{
	case PERC_INT:
		short n;
		fread(&n,sizeof(short),1,bin3ds);
		f=float(n)/100.0f;
		break;
	case PERC_FLOAT	: 
		fread(&f,sizeof(float),1,bin3ds);
		break;
	default:
		break;
	}
		
	fseek(bin3ds, findex, SEEK_SET);

}
//void RayTrace::C3DS_Loader::IntChunkProcessor( long length, long findex, int& n)
//{
//	// move the file pointer to the beginning of the main
//	// chunk's data findex + the size of the header
//
//	ChunkHeader h;
//	fseek(bin3ds, findex, SEEK_SET);
//	
//	fread(&h.id,sizeof(h.id),1,bin3ds);
//	fread(&h.len,sizeof(h.len),1,bin3ds);
//
//		// Determine the format of the color and load it
//		switch (h.id)
//		{
//	fread(&n,sizeof(int),1,bin3ds);
//	fseek(bin3ds, findex, SEEK_SET);
//}
//
//void RayTrace::C3DS_Loader::FloatChunkProcessor( long length, long findex, float& )
//{
//	
//}
void C3DS_Loader::CalculateNormals()
{
	// Let's build some normals
	for (size_t i = 0; i < pScene->GetObjectsNum(); i++)
	{
		for (size_t g = 0; g < pScene->mObjects[i].GetVertexsNum(); g++)
		{
			// Reduce each vert's normal to unit
			float length;
			vector3 unit;

			unit=pScene->mObjects[i].Normals[g];

			//unit.y = pScene->Objects[i].Normals[g].y;
			//unit.z = pScene->Objects[i].Normals[g].z;

			length = (float)sqrt((unit.x*unit.x) + (unit.y*unit.y) + (unit.z*unit.z));

			if (fabs(length) < MMIN)//?
				length = 1.0f;

			unit.x /= length;
			unit.y /= length;
			unit.z /= length;

			pScene->mObjects[i].Normals[g].x = unit.x;
			pScene->mObjects[i].Normals[g].y = unit.y;
			pScene->mObjects[i].Normals[g].z = unit.z;
		}
	}
}

void C3DS_Loader::MainChunkProcessor(long length, long findex)
{
	ChunkHeader h;

	// move the file pointer to the beginning of the main
	// chunk's data findex + the size of the header
	fseek(bin3ds, findex, SEEK_SET);

	while (ftell(bin3ds) < (findex + length - 6))
	{
		fread(&h.id,sizeof(h.id),1,bin3ds);
		fread(&h.len,sizeof(h.len),1,bin3ds);

		switch (h.id)
		{
			// This is the mesh information like vertices, faces, and materials
		case EDIT3DS	:
			EditChunkProcessor(h.len, ftell(bin3ds));
			break;
			// I left this in case anyone gets very ambitious
		case KEYF3DS	:
			//KeyFrameChunkProcessor(h.len, ftell(bin3ds));
			break;
		default			:
			break;
		}

		fseek(bin3ds, (h.len - 6), SEEK_CUR);
	}

	// move the file pointer back to where we got it so
	// that the ProcessChunk() which we interrupted will read
	// from the right place
	fseek(bin3ds, findex, SEEK_SET);
}

void C3DS_Loader::EditChunkProcessor(long length, long findex)
{
	ChunkHeader h;

	unsigned int numObjects=0;
	unsigned int numMaterials=0;
	// move the file pointer to the beginning of the main
	// chunk's data findex + the size of the header
	fseek(bin3ds, findex, SEEK_SET);

	// First count the number of Objects and Materials
	while (ftell(bin3ds) < (findex + length - 6))
	{
		fread(&h.id,sizeof(h.id),1,bin3ds);
		fread(&h.len,sizeof(h.len),1,bin3ds);

		switch (h.id)
		{
		case OBJECT	:
			numObjects++;
			break;
		case MATERIAL	:
			numMaterials++;
			break;
		default			:
			break;
		}

		fseek(bin3ds, (h.len - 6), SEEK_CUR);
	}

	// Now load the materials
	if (numMaterials > 0)
	{
		pScene->mMaterials.resize(numMaterials);

		// Material is set to untextured until we find otherwise
	/*	for (int d = 0; d < numMaterials; d++)
			pScene->Materials[d].textured = false;*/

		fseek(bin3ds, findex, SEEK_SET);

		unsigned int i = 0;

		while (ftell(bin3ds) < (findex + length - 6))
		{
			fread(&h.id,sizeof(h.id),1,bin3ds);
			fread(&h.len,sizeof(h.len),1,bin3ds);

			switch (h.id)
			{
			case MATERIAL	:
				MaterialChunkProcessor(h.len, ftell(bin3ds), pScene->mMaterials[i]);//
				i++;
				break;
			default			:
				break;
			}

			fseek(bin3ds, (h.len - 6), SEEK_CUR);
		}
	}

	// Load the Objects (individual meshes in the whole model)
	if (numObjects > 0)
	{
		pScene->mObjects.resize(numObjects);

		// Set the textured variable to false until we find a texture
		for (unsigned int k = 0; k < numObjects; ++k)
			pScene->mObjects[k].textured = false;

		// Zero the objects position and rotation
		for (unsigned int m = 0; m < numObjects; m++)
		{
			pScene->mObjects[m].pos.x = 0.0f;
			pScene->mObjects[m].pos.y = 0.0f;
			pScene->mObjects[m].pos.z = 0.0f;

			pScene->mObjects[m].rot.x = 0.0f;
			pScene->mObjects[m].rot.y = 0.0f;
			pScene->mObjects[m].rot.z = 0.0f;
		}

		// Zero out the number of texture coords
		//for (int n = 0; n < numObjects; n++)
		//	pScene->Objects[n].TexCoords.resize(0);

		fseek(bin3ds, findex, SEEK_SET);

		unsigned int j = 0;

		while (ftell(bin3ds) < (findex + length - 6))
		{
			fread(&h.id,sizeof(h.id),1,bin3ds);
			fread(&h.len,sizeof(h.len),1,bin3ds);

			switch (h.id)
			{
			case OBJECT	:
				ObjectChunkProcessor(h.len, ftell(bin3ds), pScene->mObjects[j]);
				j++;
				break;
			default			:
				break;
			}

			fseek(bin3ds, (h.len - 6), SEEK_CUR);
		}
	}

	// move the file pointer back to where we got it so
	// that the ProcessChunk() which we interrupted will read
	// from the right place
	fseek(bin3ds, findex, SEEK_SET);
}

void C3DS_Loader::MaterialChunkProcessor(long length, long findex, CMaterial& mat)
{
	ChunkHeader h;

	// move the file pointer to the beginning of the main
	// chunk's data findex + the size of the header
	fseek(bin3ds, findex, SEEK_SET);

	while (ftell(bin3ds) < (findex + length - 6))
	{
		fread(&h.id,sizeof(h.id),1,bin3ds);
		fread(&h.len,sizeof(h.len),1,bin3ds);

		switch (h.id)
		{
		case MAT_NAME	:
			// Loads the material's names
			MaterialNameChunkProcessor(h.len, ftell(bin3ds), mat);
			break;
		case MAT_AMBIENT	:
			ColorChunkProcessor(h.len, ftell(bin3ds),mat.m_ambient);
			break;
		case MAT_DIFFUSE	:
			//DiffuseColorChunkProcessor(h.len, ftell(bin3ds), mat);
			ColorChunkProcessor(h.len, ftell(bin3ds), mat.m_diffuse);
			break;
		case MAT_SPECULAR	:
			//ColorChunkProcessor(h.len, ftell(bin3ds));
			ColorChunkProcessor(h.len, ftell(bin3ds), mat.m_specular);
			break;
		case MAT_SHININESS:
			PercentChunkProcessor(h.len,ftell(bin3ds),mat.m_shininess);
			break;
//		case MAT_EMISSIVE:
//			break;
		case TRANS_PERC:
			PercentChunkProcessor(h.len,ftell(bin3ds),mat.m_transparence);
			break;
		case MAT_TEXMAP	:
			// Finds the names of the textures of the material and loads them
			TextureMapChunkProcessor(h.len, ftell(bin3ds), mat);
			break;
		default			:
			break;
		}

		fseek(bin3ds, (h.len - 6), SEEK_CUR);
	}

	// move the file pointer back to where we got it so
	// that the ProcessChunk() which we interrupted will read
	// from the right place
	fseek(bin3ds, findex, SEEK_SET);
}

void C3DS_Loader::MaterialNameChunkProcessor(long length, long findex,CMaterial& mat)
{
	// move the file pointer to the beginning of the main
	// chunk's data findex + the size of the header
	fseek(bin3ds, findex, SEEK_SET);

	// Read the material's name
	char name[80];
	for (int i = 0; i < 80; i++)
	{
		name[i] = fgetc(bin3ds);
		if (name[i] == 0)
		{
			name[i] = NULL;
			break;
		}
	}
	name[79]=NULL;
	mat.SetName(name);

	// move the file pointer back to where we got it so
	// that the ProcessChunk() which we interrupted will read
	// from the right place
	fseek(bin3ds, findex, SEEK_SET);
}

//void C3DS_Loader::DiffuseColorChunkProcessor(long length, long findex, CMaterial &mat)
//{
//	ChunkHeader h;
//
//	// move the file pointer to the beginning of the main
//	// chunk's data findex + the size of the header
//	fseek(bin3ds, findex, SEEK_SET);
//
//	while (ftell(bin3ds) < (findex + length - 6))
//	{
//		fread(&h.id,sizeof(h.id),1,bin3ds);
//		fread(&h.len,sizeof(h.len),1,bin3ds);
//
//		// Determine the format of the color and load it
//		switch (h.id)
//		{
//		case COLOR_RGB	:
//			// A rgb float color chunk
//			FloatColorChunkProcessor(h.len, ftell(bin3ds), mat);
//			break;
//		case COLOR_TRU	:
//			// A rgb int color chunk
//			IntColorChunkProcessor(h.len, ftell(bin3ds), mat);
//			break;
//		case COLOR_RGBG	:
//			// A rgb gamma corrected float color chunk
//			FloatColorChunkProcessor(h.len, ftell(bin3ds), mat);
//			break;
//		case COLOR_TRUG	:
//			// A rgb gamma corrected int color chunk
//			IntColorChunkProcessor(h.len, ftell(bin3ds), mat);
//			break;
//		default			:
//			break;
//		}
//
//		fseek(bin3ds, (h.len - 6), SEEK_CUR);
//	}
//
//	// move the file pointer back to where we got it so
//	// that the ProcessChunk() which we interrupted will read
//	// from the right place
//	fseek(bin3ds, findex, SEEK_SET);
//}

void C3DS_Loader::FloatColorChunkProcessor(long length, long findex, vector4& vec4)
{
	fseek(bin3ds, findex, SEEK_SET);
	float r;
	float g;
	float b;

	// move the file pointer to the beginning of the main
	// chunk's data findex + the size of the header
	fseek(bin3ds, findex, SEEK_SET);

	fread(&r,sizeof(r),1,bin3ds);
	fread(&g,sizeof(g),1,bin3ds);
	fread(&b,sizeof(b),1,bin3ds);

	vec4.x =r;
	vec4.y =g;
	vec4.z =b;
	vec4.w =0.0f;


	// move the file pointer back to where we got it so
	// that the ProcessChunk() which we interrupted will read
	// from the right place
	fseek(bin3ds, findex, SEEK_SET);
}

void C3DS_Loader::IntColorChunkProcessor(long length, long findex,  vector4& vec4)
{
	unsigned char r;
	unsigned char g;
	unsigned char b;

	// move the file pointer to the beginning of the main
	// chunk's data findex + the size of the header
	fseek(bin3ds, findex, SEEK_SET);

	fread(&r,sizeof(r),1,bin3ds);
	fread(&g,sizeof(g),1,bin3ds);
	fread(&b,sizeof(b),1,bin3ds);

	//Materials[matindex].color.r = r;
	//Materials[matindex].color.g = g;
	//Materials[matindex].color.b = b;
	//Materials[matindex].color.a = 255;

	vec4.x =float(r)/255.0f;
	vec4.y =float(g)/255.0f;
	vec4.z =float(b)/255.0f;
	vec4.w =0.0f;

	// move the file pointer back to where we got it so
	// that the ProcessChunk() which we interrupted will read
	// from the right place
	fseek(bin3ds, findex, SEEK_SET);
}

void C3DS_Loader::TextureMapChunkProcessor(long length, long findex, CMaterial& mat)
{
	ChunkHeader h;

	// move the file pointer to the beginning of the main
	// chunk's data findex + the size of the header
	fseek(bin3ds, findex, SEEK_SET);

	while (ftell(bin3ds) < (findex + length - 6))
	{
		fread(&h.id,sizeof(h.id),1,bin3ds);
		fread(&h.len,sizeof(h.len),1,bin3ds);

		switch (h.id)
		{
		case MAT_MAPNAME:
			// Read the name of texture in the Diffuse Color map
			MapNameChunkProcessor(h.len, ftell(bin3ds), mat);
			break;
		default			:
			break;
		}

		fseek(bin3ds, (h.len - 6), SEEK_CUR);
	}

	// move the file pointer back to where we got it so
	// that the ProcessChunk() which we interrupted will read
	// from the right place
	fseek(bin3ds, findex, SEEK_SET);
}

void C3DS_Loader::MapNameChunkProcessor(long length, long findex, CMaterial& mat)
{
	char name[80];

	// move the file pointer to the beginning of the main
	// chunk's data findex + the size of the header
	fseek(bin3ds, findex, SEEK_SET);

	// Read the name of the texture
	for (int i = 0; i < 80; i++)
	{
		name[i] = fgetc(bin3ds);
		if (name[i] == 0)
		{
			name[i] = NULL;
			break;
		}
	}
	name[79]=NULL;

	// Load the name and indicate that the material has a texture
	char fullname[80];
	sprintf(fullname, "%s%s", mPath.c_str(), name);
	mat.SetTexture(fullname);
	mat.EnableTexture(true);

	//Materials[matindex].tex.Load(fullname);
	//Materials[matindex].textured = true;

	// move the file pointer back to where we got it so
	// that the ProcessChunk() which we interrupted will read
	// from the right place
	fseek(bin3ds, findex, SEEK_SET);
}

void C3DS_Loader::ObjectChunkProcessor(long length, long findex, Object& obj)
{
	ChunkHeader h;

	// move the file pointer to the beginning of the main
	// chunk's data findex + the size of the header
	fseek(bin3ds, findex, SEEK_SET);

	// Load the object's name
	char name[80];
	for (int i = 0; i < 80; i++)
	{
		name[i] = fgetc(bin3ds);
		if (name[i] == 0)
		{
			name[i] = NULL;
			break;
		}
	}
	name[79]=NULL;
	obj.name=string(name);

	while (ftell(bin3ds) < (findex + length - 6))
	{
		fread(&h.id,sizeof(h.id),1,bin3ds);
		fread(&h.len,sizeof(h.len),1,bin3ds);

		switch (h.id)
		{
		case TRIG_MESH	:
			// Process the triangles of the object
			TriangularMeshChunkProcessor(h.len, ftell(bin3ds), obj);
			break;
		default			:
			break;
		}

		fseek(bin3ds, (h.len - 6), SEEK_CUR);
	}

	// move the file pointer back to where we got it so
	// that the ProcessChunk() which we interrupted will read
	// from the right place
	fseek(bin3ds, findex, SEEK_SET);
}

void C3DS_Loader::TriangularMeshChunkProcessor(long length, long findex, Object& obj)
{
	ChunkHeader h;

	// move the file pointer to the beginning of the main
	// chunk's data findex + the size of the header
	fseek(bin3ds, findex, SEEK_SET);

	while (ftell(bin3ds) < (findex + length - 6))
	{
		fread(&h.id,sizeof(h.id),1,bin3ds);
		fread(&h.len,sizeof(h.len),1,bin3ds);

		switch (h.id)
		{
		case VERT_LIST	:
			// Load the vertices of the onject
			VertexListChunkProcessor(h.len, ftell(bin3ds), obj);
			break;
		case LOCAL_COORDS	:
			//LocalCoordinatesChunkProcessor(h.len, ftell(bin3ds));
			break;
		case TEX_VERTS	:
			// Load the texture coordinates for the vertices
			TexCoordsChunkProcessor(h.len, ftell(bin3ds), obj);
			//obj.textured = true;
			break;
		default	:
			break;
		}

		fseek(bin3ds, (h.len - 6), SEEK_CUR);
	}

	// After we have loaded the vertices we can load the faces
	fseek(bin3ds, findex, SEEK_SET);

	while (ftell(bin3ds) < (findex + length - 6))
	{
		fread(&h.id,sizeof(h.id),1,bin3ds);
		fread(&h.len,sizeof(h.len),1,bin3ds);

		switch (h.id)
		{
		case FACE_DESC	:
			// Load the faces of the object
			FacesDescriptionChunkProcessor(h.len, ftell(bin3ds), obj);
			break;
		default			:
			break;
		}

		fseek(bin3ds, (h.len - 6), SEEK_CUR);
	}

	// move the file pointer back to where we got it so
	// that the ProcessChunk() which we interrupted will read
	// from the right place
	fseek(bin3ds, findex, SEEK_SET);
}

void C3DS_Loader::VertexListChunkProcessor(long length, long findex, Object& obj)
{
	unsigned short numVerts;

	// move the file pointer to the beginning of the main
	// chunk's data findex + the size of the header
	fseek(bin3ds, findex, SEEK_SET);

	// Read the number of vertices of the object

	fread(&numVerts,sizeof(numVerts),1,bin3ds);

	// Allocate arrays for the vertices and normals
	obj.Vertices.resize(numVerts);
	obj.Normals.assign(numVerts,vector3(0,0,0));

	// Assign the number of vertices for future use
	//obj.numVerts = numVerts;

	// Zero out the normals array
	//for (int j = 0; j < obj.Vertexes.size() ; j++)
	//			obj.Normals[j] = 0.0f;

	// Read the vertices, switching the y and z coordinates aand changing the sign of the z coordinate
	for (unsigned int i = 0; i < obj.Vertices.size(); ++i)
	{
		fread(&obj.Vertices[i].x,sizeof(float),1,bin3ds);
		fread(&obj.Vertices[i].z,sizeof(float),1,bin3ds);//the order is special
		fread(&obj.Vertices[i].y,sizeof(float),1,bin3ds);

		// Change the sign of the z coordinate
		obj.Vertices[i].z = -obj.Vertices[i].z;
	}

	// move the file pointer back to where we got it so
	// that the ProcessChunk() which we interrupted will read
	// from the right place
	fseek(bin3ds, findex, SEEK_SET);
}

void C3DS_Loader::TexCoordsChunkProcessor(long length, long findex, Object& obj)
{
	// The number of texture coordinates
	unsigned short numCoords;

	// move the file pointer to the beginning of the main
	// chunk's data findex + the size of the header
	fseek(bin3ds, findex, SEEK_SET);

	// Read the number of coordinates
	fread(&numCoords,sizeof(numCoords),1,bin3ds);

	// Allocate an array to hold the texture coordinates
	obj.TexCoords.resize(numCoords);

	
	// Read teh texture coordiantes into the array
	for (size_t i = 0; i < obj.TexCoords.size(); ++i)
	{
		fread(&obj.TexCoords[i].u,sizeof(float),1,bin3ds);
		fread(&obj.TexCoords[i].v,sizeof(float),1,bin3ds);
	}

	// move the file pointer back to where we got it so
	// that the ProcessChunk() which we interrupted will read
	// from the right place
	fseek(bin3ds, findex, SEEK_SET);
}

void C3DS_Loader::FacesDescriptionChunkProcessor(long length, long findex, Object& obj)
{
	ChunkHeader h;
	unsigned short numFaces;	// The number of faces in the object
	unsigned short vertA;		// The first vertex of the face
	unsigned short vertB;		// The second vertex of the face
	unsigned short vertC;		// The third vertex of the face
	unsigned short flags;		// The winding order flags
	long subs;					// Holds our place in the file
	int numMatFaces = 0;		// The number of different materials

	// move the file pointer to the beginning of the main
	// chunk's data findex + the size of the header
	fseek(bin3ds, findex, SEEK_SET);

	// Read the number of faces
	fread(&numFaces,sizeof(numFaces),1,bin3ds);

	// Allocate an array to hold the faces
	obj.Faces.resize(numFaces);
	//Objects[objindex].Faces = new GLushort[numFaces * 3];
	// Store the number of faces
	//Objects[objindex].numFaces = numFaces * 3;

	// Read the faces into the array
	for (size_t i = 0; i < obj.Faces.size(); ++i)
	{
		// Read the vertices of the face
		fread(&vertA,sizeof(vertA),1,bin3ds);
		fread(&vertB,sizeof(vertB),1,bin3ds);
		fread(&vertC,sizeof(vertC),1,bin3ds);
		fread(&flags,sizeof(flags),1,bin3ds);

		// Place them in the array
		obj.Faces[i].v1 = vertA;
		obj.Faces[i].v2 = vertB;
		obj.Faces[i].v3 = vertC;

		// Calculate the face's normal
		vector3 n;
		vector3 v1=obj.Vertices[vertA];
		vector3 v2=obj.Vertices[vertB];
		vector3 v3=obj.Vertices[vertC];

	// calculate the normal
		vector3 u,v;
	//	float u[3], v[3];

		// V3 - V2 ;
		u=v3-v2;
		/*u[0] = v3.x - v2.x ;
		u[1] = v3.y - v2.y;
		u[2] = v3.z - v2.z;*/

		//  V1 - V2 ;
		v=v1-v2;
		/*v[0] = v2.x - v1.x;
		v[1] = v2.y - v1.y;
		v[2] = v2.z - v1.z;*/

		n=vector3::Cross(u,v);
		/*n.x = (u[1]*v[2] - u[2]*v[1]);
		n.y = (u[2]*v[0] - u[0]*v[2]);
		n.z = (u[0]*v[1] - u[1]*v[0]);*/

		// Add this normal to its verts' normals
		obj.Normals[vertA]   += n;
		obj.Normals[vertB]   += n;
		obj.Normals[vertC]   += n;


		/*Objects[objindex].Normals[vertB*3]   = n.x;
		Objects[objindex].Normals[vertB*3+1] += n.y;
		Objects[objindex].Normals[vertB*3+2] += n.z;
		Objects[objindex].Normals[vertC*3]   += n.x;
		Objects[objindex].Normals[vertC*3+1] += n.y;
		Objects[objindex].Normals[vertC*3+2] += n.z;*/
	}

	// Store our current file position
	subs = ftell(bin3ds);

	// Check to see how many materials the faces are split into
	while (ftell(bin3ds) < (findex + length - 6))
	{
		fread(&h.id,sizeof(h.id),1,bin3ds);
		fread(&h.len,sizeof(h.len),1,bin3ds);

		switch (h.id)
		{
		case FACE_MAT	:
			//FacesMaterialsListChunkProcessor(h.len, ftell(bin3ds), objindex);
			numMatFaces++;
			break;
		default			:
			break;
		}

		fseek(bin3ds, (h.len - 6), SEEK_CUR);
	}

	// Split the faces up according to their materials
	if (numMatFaces > 0)
	{
		obj.textured=true;
		// Allocate an array to hold the lists of faces divided by material
		obj.MatFaces.resize(numMatFaces);
		// Store the number of material faces
		//Objects[objindex].numMatFaces = numMatFaces;

		fseek(bin3ds, subs, SEEK_SET);

		int j = 0;

		// Split the faces up
		while (ftell(bin3ds) < (findex + length - 6))
		{
			fread(&h.id,sizeof(h.id),1,bin3ds);
			fread(&h.len,sizeof(h.len),1,bin3ds);

			switch (h.id)
			{
			case FACE_MAT	:
				// Process the faces and split them up
				FacesMaterialsListChunkProcessor(h.len, ftell(bin3ds), obj, j);
				j++;
				break;
			default			:
				break;
			}

			fseek(bin3ds, (h.len - 6), SEEK_CUR);
		}
	}

	// move the file pointer back to where we got it so
	// that the ProcessChunk() which we interrupted will read
	// from the right place
	fseek(bin3ds, findex, SEEK_SET);
}

void C3DS_Loader::FacesMaterialsListChunkProcessor(long length, long findex,Object& obj, int subfacesindex)
{
	char name[80];				// The material's name
	unsigned short numEntries;	// The number of faces associated with this material
	unsigned short Face;		// Holds the faces as they are read
				// An index to the Materials array for this material

	// move the file pointer to the beginning of the main
	// chunk's data findex + the size of the header
	fseek(bin3ds, findex, SEEK_SET);

	// Read the material's name
	for (int i = 0; i < 80; i++)
	{
		name[i] = fgetc(bin3ds);
		if (name[i] == 0)
		{
			name[i] = NULL;
			break;
		}
	}
	name[79]=NULL;

	// Faind the material's index in the Materials array
	size_t index;
	for (index = 0; index < pScene->mMaterials.size(); ++index)
	{
		if (strcmp(name, pScene->mMaterials[index].GetName().c_str()) == 0)
			break;
	}

	// Store this value for later so that we can find the material
	obj.MatFaces[subfacesindex].MatIndex = index;

	// Read the number of faces associated with this material
	fread(&numEntries,sizeof(numEntries),1,bin3ds);

	// Allocate an array to hold the list of faces associated with this material

	obj.MatFaces[subfacesindex].subFaces.resize(numEntries);
	// Store this number for later use
	//Objects[objindex].MatFaces[subfacesindex].numSubFaces = numEntries * 3;

	// Read the faces into the array
	for (size_t i = 0; i < numEntries; ++i)
	{
		// read the face
		fread(&Face,sizeof(Face),1,bin3ds);
		// Add the face's vertices to the list
		obj.MatFaces[subfacesindex].subFaces[i] = Face;
		obj.Faces[Face].MatIndex=obj.MatFaces[subfacesindex].MatIndex;

		/*Objects[objindex].MatFaces[subfacesindex].subFaces[i+1] = Objects[objindex].Faces[Face * 3 + 1];
		Objects[objindex].MatFaces[subfacesindex].subFaces[i+2] = Objects[objindex].Faces[Face * 3 + 2];*/
	}

	// move the file pointer back to where we got it so
	// that the ProcessChunk() which we interrupted will read
	// from the right place
	fseek(bin3ds, findex, SEEK_SET);
}
